package com.csun.cmny.provider.device.patrol;

import com.csun.cmny.provider.device.patrol.entity.PatrolCmdEntity;
import com.csun.cmny.provider.model.domain.*;
import com.csun.cmny.provider.service.*;
import com.csun.cmny.util.PublicUtil;
import com.google.common.collect.Lists;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Hex;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Calendar;
import java.util.List;

/**
 * @Auther: chisj chisj@foxmal.com
 * @Date: 2021/7/22 11:35
 * @Description: 巡更棒数据处理类
 */
@Slf4j
@Component
public class PatrolMessageHandler {

    @Resource
    private DmcPatrolRecordService dmcPatrolRecordService;
    @Resource
    private DmcPatrolReminderService dmcPatrolReminderService;
    @Resource
    private DmcDeviceService dmcDeviceService;
    @Resource
    private DmcPatrolDataService dmcPatrolDataService;
    @Resource
    private DmcPatrolGreatLocationService dmcPatrolGreatLocationService;
    @Resource
    private DmcPatrolPointLocationService dmcPatrolPointLocationService;

    /**
     * 处理巡更棒消息
     *
     * @param ctx   the channel handler context
     * @param patrolCmdEntity  the patrol cmd entity
     * @参考文档    通讯协议V2.1.0
     */
    public void handler(ChannelHandlerContext ctx, PatrolCmdEntity patrolCmdEntity) {

        // 获取消息类型
        //String type = PatrolMessageDecoder.getMessageType(data);
//        if (type == null) {
//            return;
//        }

        switch (patrolCmdEntity.cmd) {
            case 0xb0 :     // 发送 SIM 卡 ICCID
                dealPatrolIccidMsg(ctx, patrolCmdEntity);
                break;
            case 0xb1 :     // 读卡数据消息
                dealPatrolReadCardMsg(ctx, patrolCmdEntity);
                break;
            case 0xb2 :     // 巡更棒校时
                dealPatrolTimeMsg(ctx, patrolCmdEntity);
                break;
            case 0xb9 :     // 长按SOS键
                log.info("patrol receive sos msg...");
                break;
            case 0xd0 :     // 查询命令
                dealPatrolCmdMsg(ctx, patrolCmdEntity);
                break;
            default :
                log.error("patrol cmd 未识别的消息... {}",
                        String.format("%02x", (byte)patrolCmdEntity.cmd));
        }
    }

    /**
     * 巡更棒查询命令
     *
     * @param ctx
     * @param patrolCmdEntity
     */
    private void dealPatrolCmdMsg(ChannelHandlerContext ctx, PatrolCmdEntity patrolCmdEntity) {

        byte[] ack = PatrolMessageEncoder.buildCmdAckMsg();
        log.info("# patrol cmd ack msg...：   [{}] ...", PatrolMessageDecoder.format(Hex.encodeHexString(ack)));
        ctx.writeAndFlush(Unpooled.copiedBuffer(ack));
    }

    /**
     * 巡更棒校时
     *
     * @param ctx
     * @param patrolCmdEntity
     */
    private void dealPatrolTimeMsg(ChannelHandlerContext ctx, PatrolCmdEntity patrolCmdEntity) {

        byte[] ack = PatrolMessageEncoder.buildTimeAckMsg();
        log.info("# patrol time ack msg...：   [{}] ...", PatrolMessageDecoder.format(Hex.encodeHexString(ack)));
        ctx.writeAndFlush(Unpooled.copiedBuffer(ack));
    }

    /**
     * 处理ICCID消息
     *
     * @param ctx
     * @param patrolCmdEntity
     */
    public void dealPatrolIccidMsg(ChannelHandlerContext ctx, PatrolCmdEntity patrolCmdEntity) {

        // 数据内容 = 20个ASCII码 + 4个巡检器号
        byte[] iccid = new byte[20];
        byte[] deviceNo = new byte[4];
        System.arraycopy(patrolCmdEntity.data, 0, iccid, 0, 20);
        System.arraycopy(patrolCmdEntity.data, patrolCmdEntity.length - 5, deviceNo, 0, 4);
        String sn = Hex.encodeHexString(deviceNo);
        String str_iccid = new String(iccid);

        log.info("deal patrol iccid msg, iccid = {}, sn = {}", str_iccid, sn);

        DmcDevice dmcDevice = dmcDeviceService.queryDeviceByNumber(sn);
        if (PublicUtil.isEmpty(dmcDevice)) {
            log.error("=====> patrol great sn is not exist.");
            return ;
        }
        DmcPatrolGreatLocation location = dmcPatrolGreatLocationService.selectByKey(dmcDevice.getId());
        if (PublicUtil.isEmpty(location)) {
            log.error("=====> patrol great not bind.");
            return ;
        }
        Integer result = savePatrolDataIccid(dmcDevice, str_iccid);
    }

    /**
     * 处理巡更棒读卡数据
     *
     * @param ctx
     * @param patrolCmdEntity
     */
    public void dealPatrolReadCardMsg(ChannelHandlerContext ctx, PatrolCmdEntity patrolCmdEntity) {

        // 数据内容 = 电量(2) + 巡检器号(4) + 数据(n*11)
        // 电量 : ２位 比如 0x40 0x23 表示 4.023V (电压范围为 3.3-4.2V)
        byte[] svg = new byte[2];
        // 巡检器号 : 长度为 4, ４个 16 进制的号码
        byte[] deviceNo = new byte[4];
        // 数据 : n 最大为8最小为1 一次最多可以传8条记录
        int n = patrolCmdEntity.length / 11;
        // byte[][] record = new byte[n][11];

        System.arraycopy(patrolCmdEntity.data, 0, svg, 0, 2);
        System.arraycopy(patrolCmdEntity.data, 2, deviceNo, 0, 4);

        String sn = Hex.encodeHexString(deviceNo);
        String str_svg = svgConvert(svg);

        log.info("deal patrol read card msg, svg = {}, sn = {}, n = {}", str_svg, sn, n);

        //int i = 0;
        List<DmcPatrolRecord> dmcPatrolRecordList = Lists.newArrayList();
        for (int i = 0; i < n; i++) {
            // 前６位是时间 分别为 年(后２位), 月，日，时，分，秒，
            // 例如 0x19 0x06 0x30 0x02 0x08 0x16 表示 2019-6-30 2:8:16
            // 后５位是卡 ID
            byte[] time = new byte[6];
            byte[] point_no = new byte[5];

            System.arraycopy(patrolCmdEntity.data, 6 + i * 11, time, 0, 6);
            System.arraycopy(patrolCmdEntity.data, 12 + i * 11, point_no, 0, 5);

            String str_point_no = Hex.encodeHexString(point_no).toUpperCase();
            String str_time = timeConvert(time);

            log.info("record {} time = {}, pointNo = {}", i, str_time, str_point_no);

            DmcPatrolRecord record = new DmcPatrolRecord();
            record.setPointNo(str_point_no);
            record.setPatrolTime(str_time);
            dmcPatrolRecordList.add(record);
        }

        // 回复消息
        byte status = 'Y';
        byte[] ack = PatrolMessageEncoder.buildCardReadAckMsg(patrolCmdEntity, status);
        log.info("# patrol ack msg...：   [{}] ...", PatrolMessageDecoder.format(Hex.encodeHexString(ack)));
        ctx.writeAndFlush(Unpooled.copiedBuffer(ack));

        // 校验巡更棒编号 & 巡更点编号
        DmcDevice greatDevice = dmcDeviceService.queryDeviceByNumber(sn);
        if (PublicUtil.isEmpty(greatDevice)) {
            log.error("=====> patrol great sn is not exist.");
            return ;
        }
        DmcPatrolGreatLocation greatLocation = dmcPatrolGreatLocationService.selectByKey(greatDevice.getId());
        if (PublicUtil.isEmpty(greatLocation)) {
            log.error("=====> patrol great not bind.");
            return ;
        }
        Integer result = savePatrolDataSvg(greatDevice, str_svg);

        for (DmcPatrolRecord dpr : dmcPatrolRecordList) {
            DmcDevice pointDevice = dmcDeviceService.queryDeviceByNumber(dpr.getPointNo());
            if (PublicUtil.isEmpty(pointDevice)) {
                log.error("=====> patrol point no is not exist.");
                continue ;
            }
            DmcPatrolPointLocation pointLocation = dmcPatrolPointLocationService.selectByKey(pointDevice.getId());
            if (PublicUtil.isEmpty(pointLocation)) {
                log.error("=====> patrol point not bind.");
                continue ;
            }

            dpr.setGreatId(greatDevice.getId());
            dpr.setGreatNo(greatDevice.getDeviceNo());
            dpr.setGroupId(greatDevice.getGroupId());
            dpr.setUserId(greatLocation.getUserId());
            dpr.setUserName(greatLocation.getUserName());
            dpr.setPointId(pointDevice.getId());
            dpr.setPointNo(pointDevice.getDeviceNo());
            dpr.setLocation(pointLocation.getLocation());

            /**
             * @author  chisj
             * @date    2021-08-03 16:48
             * @desc    在同一个机构才会产生巡更记录
             */
            if (greatDevice.getGroupId().equals(pointDevice.getGroupId())) {

                // 存储巡更记录
                dmcPatrolRecordService.save(dpr);

                // 更新巡更提醒
                dmcPatrolReminderService.updateWait(greatDevice.getId(), pointDevice.getId(), dpr.getPatrolTime());
            }
        }
    }

    /**
     * 转换电量
     *
     * @param data
     *
     * @return
     */
    String svgConvert(byte[] data) {

        // 0x40 0x23 表示 4.023V (电压范围为 3.3-4.2V)
        String svg = Hex.encodeHexString(data);
        StringBuffer sb = new StringBuffer(svg);
        sb.insert(1, ".");
        return sb.toString();
    }

    /**
     * 转换时间
     */
    String timeConvert(byte[] data) {

        // SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        // 0x19 0x06 0x30 0x02 0x08 0x16 表示 2019-6-30 2:8:16
        Calendar calendar = Calendar.getInstance();
        String year_prefix = String.valueOf(calendar.get(Calendar.YEAR));
        year_prefix = year_prefix.substring(0, 2);
        String year = year_prefix + String.format("%02x", data[0]);

//        calendar.set(Integer.parseInt(year),
//                Integer.parseInt(String.format("%02x", data[1])),
//                Integer.parseInt(String.format("%02x", data[2])),
//                Integer.parseInt(String.format("%02x", data[3])),
//                Integer.parseInt(String.format("%02x", data[4])),
//                Integer.parseInt(String.format("%02x", data[5])));

//        return sdf.format(calendar.getTime());
        return String.format("%s-%02x-%02x %02x:%02x:%02x",
                year, data[1], data[2], data[3], data[4], data[5]);
    }

    /**
     * 根据sn校验设备信息
     *
     * @param sn
     *
     * @return
     */
    public DmcDevice checkPatrolGreatBySn(String sn) {
        DmcDevice dmcDevice = dmcDeviceService.queryDeviceByNumber(sn);
        if (PublicUtil.isEmpty(dmcDevice)) {
            log.error("=====> patrol great sn is not exist.");
            return null;
        }
        DmcPatrolGreatLocation location = dmcPatrolGreatLocationService.selectByKey(dmcDevice.getId());
        if (PublicUtil.isEmpty(location)) {
            log.error("=====> patrol great not bind.");
            return null;
        }
        return dmcDevice;
    }

    /**
     * 保存巡更棒iccid
     *
     * @param dmcDevice the dmc device
     * @param iccid the iccid
     *
     * @return  the int.
     */
    private Integer savePatrolDataIccid(DmcDevice dmcDevice, String iccid) {

        DmcPatrolData dmcPatrolData = new DmcPatrolData();
        dmcPatrolData.setDeviceId(dmcDevice.getId());
        dmcPatrolData.setDeviceNo(dmcDevice.getDeviceNo());
        dmcPatrolData.setIccid(iccid);
        return dmcPatrolDataService.saveOrUpdate(dmcPatrolData);
    }

    /**
     * 保存巡更棒电压
     *
     * @param dmcDevice the dmc device
     * @param svg   the svg
     *
     * @return  the int.
     */
    private Integer savePatrolDataSvg(DmcDevice dmcDevice, String svg) {

        DmcPatrolData dmcPatrolData = new DmcPatrolData();
        dmcPatrolData.setDeviceId(dmcDevice.getId());
        dmcPatrolData.setDeviceNo(dmcDevice.getDeviceNo());
        dmcPatrolData.setSvg(svg);
        return dmcPatrolDataService.saveOrUpdate(dmcPatrolData);
    }

}
